package com.ruoyi.cs.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.domain.Response;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.*;
import com.ruoyi.cs.domain.*;
import com.ruoyi.cs.domain.vo.TBoxTitleVo;
import com.ruoyi.cs.domain.vo.TBoxVo;
import com.ruoyi.cs.mapper.*;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.cs.service.*;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.mapper.SysDictDataMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.ConnectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

/**
 * 箱子信息Service业务层处理
 *
 * @author ruoyi
 * @date 2021-03-25
 */
@Service
@SuppressWarnings("all")
public class TBoxServiceImpl implements ITBoxService
{
    private static final Logger log = LoggerFactory.getLogger(TBoxServiceImpl.class);

    @Autowired
    private TBoxMapper tBoxMapper;
    @Autowired
    private TGoodsMapper tGoodsMapper;
    @Autowired
    private TUserMapper tUserMapper;
    @Autowired
    private TBackpackMapper backpackMapper;
    @Autowired
    private TExchangeMapper tExchangeMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private RedisLock redisLock;
    @Autowired
    private TBalanceChangeMapper balanceChangeMapper;
    @Autowired
    private ITBoxTitleService titleService;
    @Autowired
    private SysConfigMapper sysConfigMapper;
    @Autowired
    private SysDictDataMapper sysDictDataMapper;
    @Autowired
    private TRechargeMapper tRechargeMapper;
    @Autowired
    private TWarReceiveMapper tWarReceiveMapper;
    @Autowired
    private ITWarService tWarService;
    @Autowired
    private TVipGradeMapper tVipGradeMapper;
    @Autowired
    private TVipUserMapper tVipUserMapper;
    @Autowired
    private ITVipUserService tVipUserService;

    /**
     * 查询箱子信息
     *
     * @param boxId 箱子信息ID
     * @return 箱子信息
     */
    @Override
    public TBoxVo selectTBoxById(String boxId)
    {
        TBoxVo tBoxVo = new TBoxVo();
        tBoxVo.setBoxId(boxId);
        List<TBoxVo> list = tBoxMapper.boxListBack(tBoxVo);
        if (list.size()>0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public TBox getInfoTbox(String boxId) {
        return tBoxMapper.selectTBoxById(boxId);
    }

    /**
     * 查询箱子信息列表
     *
     * @param tBox 箱子信息
     * @return 箱子信息
     */
    @Override
    public List<TBox> selectTBoxList(TBox tBox)
    {
        List<TBox> list = tBoxMapper.selectTBoxList(tBox);
        if (list != null && list.size()>0) {
            list.stream().forEach(bean -> {
                List<TGoods> list1 = tGoodsMapper.boxGoodsList(Constants.GOOGSBLTYPE0,bean.getBoxId());
                if (list1 != null && list1.size()>0){
                    bean.setGoodsPic(list1.get(0).getGoodsPic());
                }
            });
        }
        return list;
    }

    @Override
    public List<TBox> queryTBoxList()
    {
        return tBoxMapper.queryRobotTBoxList();
    }

    /**
     * 新增箱子信息
     *
     * @param tBox 箱子信息
     * @return 结果
     */
    @Override
    public int insertTBox(TBox tBox)
    {
        tBox.setDelFlag(Constants.FAIL);
        tBox.setCreateTime(DateUtils.getNowDate());
        if (tBox.getExcessValue() == null) {
            tBox.setExcessValue(new BigDecimal(0.05));
        }
        return tBoxMapper.insertTBox(tBox);
    }

    /**
     * 修改箱子信息
     *
     * @param tBox 箱子信息
     * @return 结果
     */
    @Override
    public int updateTBox(TBox tBox)
    {
        if (tBox.getExcessValue() == null) {
            tBox.setExcessValue(new BigDecimal(0.05));
        }
        tBox.setUpdateTime(DateUtils.getNowDate());
        return tBoxMapper.updateTBox(tBox);
    }

    /**
     * 批量删除箱子信息
     *
     * @param boxIds 需要删除的箱子信息ID
     * @return 结果
     */
    @Override
    public int deleteTBoxByIds(String[] boxIds)
    {
//        /**判断该箱子下面是否存在对应的饰品，如果存在则不能删除*/
//        int count = tGoodsMapper.bacthTGoodsCountDelete(Constants.GOOGSBLTYPE0,boxIds);
//        if (count > 0) {
//            return Constants.FAILCODE;
//        }
        return tBoxMapper.updateDelFlagTBoxByIds(Constants.DELETE,boxIds);
    }

    /**
     * 删除箱子信息信息
     *
     * @param boxId 箱子信息ID
     * @return 结果
     */
    @Override
    public int deleteTBoxById(String boxId)
    {
        return tBoxMapper.deleteTBoxById(boxId);
    }

    /**
     * 批量停用箱子信息
     * @param boxIds
     * @return
     */
    @Override
    public int bacthStopTBox(String[] boxIds) {
        /**判断该箱子下一级是否存在对应的可用饰品，如果存在则不能停用*/
//        int count = tGoodsMapper.bacthTGoodsCount(Constants.SUCCESS, Constants.GOOGSBLTYPE0,boxIds);
//        if (count > 0) {
//            return Constants.FAILCODE;
//        }

        return tBoxMapper.updateDelFlagTBoxByIds(Constants.FAIL,boxIds);
    }

    /**
     * 批量启用箱子信息
     * @param boxIds
     * @return
     */
    @Override
    public Response bacthEnableTBox(String[] boxIds) {
        /**根据箱子ID查询出对应的箱子标签是有有未启用的*/
        List<Map> goodsExitList  = tGoodsMapper.checkBoxGoodsExit(boxIds);
        if(goodsExitList.size() != boxIds.length){
            return Response.fail(Constants.FAILCODE,"选择的箱子中部分箱子下不存在饰品，请调整后再试!");
        }
        for (Map map : goodsExitList) {
            BigDecimal chance = (BigDecimal) map.get("chance");
            if(chance.compareTo(BigDecimal.ONE) != 0){
                return Response.fail(Constants.FAILCODE,"箱子ID:"+map.get("boxId")+" 饰品总概率不为1，无法满足上架条件");
            }
        }
        /**判断箱子中饰品概率是否为1*/
        tBoxMapper.updateDelFlagTBoxByIds(Constants.SUCCESS,boxIds);
        return Response.success();
    }

    /**'
     * 根据箱子ID获取对应的饰品列表
     * @param boxId
     * @return
     */
    @Override
    public List<TGoods> goodsListByBoxId(String boxId){
        TGoods tGoods = new TGoods();
        tGoods.setGoodsBelongingType(Constants.GOOGSBLTYPE0);
        tGoods.setGoodsBelongingId(boxId);
        tGoods.setDelFlag(Constants.SUCCESS);
        List<TGoods> list = tGoodsMapper.selectTGoodsList(tGoods);
        return list;
    }

    @Override
    public List<Map> goodsChance(String boxId) {
        return tGoodsMapper.goodsChance(boxId);
    }

    @Override
    public Map<String,Integer> openableNum(String userId, String boxId) {
        Map map= new HashMap<>();
        /*当日该箱开启总次数*/
        String unpackingBoxIdkey = Constants.UNPACKINGBOXIDKEY + boxId;
        Integer boxTotalNum = redisCache.getCacheObject(unpackingBoxIdkey) == null ? 0 : redisCache.getCacheObject(unpackingBoxIdkey);
        /*单人当日开启该箱总次数*/
        String SingleOpenBoxKey = Constants.UNPACKINGUSERIDKEY + userId+":"+boxId;
        Integer boxSingleNum = redisCache.getCacheObject(SingleOpenBoxKey) == null ? 0 : redisCache.getCacheObject(SingleOpenBoxKey);
        map.put("surplusTotalNum",boxTotalNum);
        map.put("surplusSingleUserNum",boxSingleNum);
        return map;
    }

//    /**
//     * 普通新用户保底开箱算法
//     * @param userId
//     * @param boxId
//     * @param num
//     * @return
//     */
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public Response<List<TGoods>> unpacking(String userId, String boxId, Integer num) {
//        if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(boxId) || StringUtils.isNull(num)) {
//            return Response.fail(Constants.FAILCODE, "参数不能为空！");
//        }
//        /**根据用户ID获取用户信息*/
//        TUser tUser = tUserMapper.selectTUserById(userId);
//
//        if (tUser == null || !Constants.SUCCESS.equals(tUser.getDelFlag())) {
//            return Response.fail(Constants.FAILCODE, "用户不存在或已被冻结，请联系管理员！");
//        }
//        /**用户余额*/
//        BigDecimal balance = tUser.getUserBalance();
//
//        /**根据箱子ID获取箱子信息*/
//        TBox tBox = tBoxMapper.selectTBoxById(boxId);
//
//        if (StringUtils.isNull(tBox)) {
//            return Response.fail(Constants.FAILCODE, "箱子不存在,请勿重复操作！");
//        }
//        if (!Constants.SUCCESS.equals(tBox.getDelFlag())) {
//            return Response.fail(Constants.FAILCODE, "箱子未上架,请勿重复操作！");
//        }
//        if (!Constants.BOXTYPE0.equals(tBox.getBoxType())) {
//            return Response.fail(Constants.FAILCODE, "所选箱子有误，请刷新页面后重试！");
//        }
//        /**箱子价格*/
//        BigDecimal price = tBox.getBoxPrice();
//        /**判断是否满足开箱条件*/
//        if (balance.compareTo(price.multiply(new BigDecimal(num))) == -1) {
//            return Response.fail(Constants.FAILCODE, "余额不足，请充值后再开箱！");
//        }
//
//        /*判断用户总资产 总资产=用户余+背包饰品总金额（不包含已兑换的）*/
//        BigDecimal userTotalAssets = backpackMapper.selectUserTotalAssets(userId);
//        userTotalAssets = userTotalAssets.add(tUser.getUserBalance());
//        Integer newUserNum = tUser.getNewUserNum();
//        List<TGoods> goodsList = new ArrayList<>();
////        String userkey = Constants.USERLOCK+tUser.getUserId();
////        String userkeyvalue = redisCache.getCacheObject(userkey);
////        if (StringUtils.isNotEmpty(userkeyvalue)) {
////            String dataflte = DateUtils.getTimeDayAfter(DateUtils.parseDate(userkeyvalue),Constants.USERKEYDAY);
////            String time = DateUtils.getDatePoor(DateUtils.parseDate(dataflte),DateUtils.getNowDate());
////            return new AjaxResult(Constants.FAILCODE,"为了您的账号安全，请"+time+"后进行该操作!");
////        }
//        String lockTime = DateUtils.getTimeAfter(DateUtils.getNowDate(), 1);
//        lockTime = Long.toString(DateUtils.parseDate(lockTime).getTime());
//        String lockKey = Constants.OPENBOXKEY + boxId;
//        boolean lockFlag1 = false;
//        try {
//            String unpackingBoxIdkey = Constants.UNPACKINGBOXIDKEY + tBox.getBoxId();
//            String SingleOpenBoxKey = Constants.UNPACKINGUSERIDKEY + tUser.getUserId() + ":" + boxId;
//            Integer boxTotalNum = 0;
//            Integer boxSingleNum = 0;
//            if (tBox.getTotalNum() != null || tBox.getSingleUserNum() != null) {
//                lockFlag1 = true;
//                /**获取锁*/
//                boolean lockflag = redisLock.lock(lockKey, lockTime);
//                if (!lockflag) {
//                    Thread.currentThread().sleep(500);
//                    lockflag = redisLock.lock(lockKey, lockTime);
//                }
//                if (lockflag) {
//                    if (tBox.getTotalNum() != null) {
//                        /*当日该箱开启总次数*/
//                        boxTotalNum = redisCache.getCacheObject(unpackingBoxIdkey) == null ? 0 : redisCache.getCacheObject(unpackingBoxIdkey);
//                        boxTotalNum = boxTotalNum + num;
//                        if (tBox.getTotalNum() < boxTotalNum) {
//                            return Response.fail("无剩余次数！");
//                        }
//                    }
//                    if (tBox.getSingleUserNum() != null) {
//                        /*单人当日开启该箱总次数*/
//                        boxSingleNum = redisCache.getCacheObject(SingleOpenBoxKey) == null ? 0 : redisCache.getCacheObject(SingleOpenBoxKey);
//                        boxSingleNum = boxSingleNum + num;
//                        if (tBox.getSingleUserNum() < boxSingleNum) {
//                            return Response.fail("无剩余次数！");
//                        }
//                    }
//                } else {
//                    log.error("获取开箱锁失败");
//                    return Response.fail("网络延迟，请重试！");
//                }
//            }
//
//            /**抽到的饰品列表*/
//            List<TGoods> resultList = new ArrayList<>();
//            if (num > 0) {
//                /**主播用户概率抽奖*/
//                if (tUser.getUserType().equals(Constants.USERTYPE1)) {
//                    /*查询主播开箱规则参数*/
//                    /**
//                     * 0 主播开箱逻辑为纯概率；
//                     * 1 主播开箱逻辑为概率+奖池，但是主播行为不叠加奖池；
//                     * 2 主播开箱逻辑为之前设置的主播开箱逻辑。
//                     */
//                    SysConfig ruleTypeConfig = sysConfigMapper.checkConfigKeyUnique("anchor_unpacking_rule_type");
//                    String ruleType = ruleTypeConfig == null || StringUtils.isEmpty(ruleTypeConfig.getConfigValue()) ? "2" : ruleTypeConfig.getConfigValue();
////                    if (Constants.ANCHORUNPACKINGRULE0.equals(ruleType)) {
////                        zbProbabilityUnpacking(boxId, num, resultList);
////                    } else if (Constants.ANCHORUNPACKINGRULE1.equals(ruleType)) {
////                        zbProbabilityJackpotUnpacking(tBox, num, resultList);
////                    } else {
////                        zbCustomizeRandomUnPacking(price.toString(), boxId, num, resultList);
////                    }
//                } else {
//                    /*开箱算法（0 天气鱼+奖池 1 保底）*/
//                    String ruleType = null;
//                    /*判断新用户次数*/
//                        /*true - 新用户规则
//                        false - 随机+奖池*/
//                    boolean rule = false;
//                    /*获取箱子等级次数*/
//                    SysDictData boxlevel = sysDictDataMapper.selectDictDataByDictCode(tBox.getBoxLevel());
//                    /*设置奖池*/
//                    BigDecimal jackpot = tBox.getJackpot() == null ? new BigDecimal(0) : tBox.getJackpot();
//                    /*利润*/
//                    BigDecimal dividend = tBox.getDividend() == null ? new BigDecimal(0) : tBox.getDividend();
//                    /*获取箱子中价格前N的商品*/
//                    Integer frontJackpotNum = tBox.getFrontJackpotNum() == null ? 5 : tBox.getFrontJackpotNum();
//                    List<String> goodsTopN = tGoodsMapper.getGoodsTopN(tBox.getBoxId(), frontJackpotNum);
//                    SysConfig jackpotProportion = sysConfigMapper.checkConfigKeyUnique("jackpot_increase_proportion");
//                    String jackpotConfigValue = jackpotProportion.getConfigValue() == null ? "1" : jackpotProportion.getConfigValue();
//                    Integer boxLevelNum = 1;
//                    for (int j = 0; j < num; j++) {
//                        rule = false;
//                        /*判断新用户次数是否大于0并且是否大于当前开箱次数*/
//                        if (boxlevel != null && StringUtils.isNotEmpty(boxlevel.getDictValue()) && Integer.valueOf(boxlevel.getDictValue()) > 0) {
//                            boxLevelNum = Integer.valueOf(boxlevel.getDictValue());
//                            if (tUser.getNewUserNum() >= boxLevelNum) {
//                                /*判断用户选择的箱子是否为等级箱*/
//                                if (StringUtils.isNotEmpty(tBox.getBoxLevel())) {
//                                    /*判断用户总资产是否小于2*/
//                                    if (userTotalAssets.compareTo(new BigDecimal(2)) < 0) {
//                                        rule = true;
//                                    }
//                                }
//                            }
//                        }
//                        log.info("箱子等级次数BOXLEVEL：{}" + boxLevelNum);
//                        /*新用户逻辑*/
//                        TGoods tGoods = null;
//                        if (rule) {
//                            log.info("触发新用户逻辑");
//                            tGoods = newUserDraw(tBox, userTotalAssets, tUser);
//                            /*满足新用户条件时扣除新用户次数*/
//                            newUserNum = newUserNum - boxLevelNum;
//                            ruleType = Constants.RULE_TYPE1;
//                            tGoods.setRuleType(ruleType);
//                            resultList.add(tGoods);
//                        } else {
//                            log.info("触发jackpot逻辑");
//                            /*概率+开箱逻辑*/
//                            /*判断用户是否已经充值，未充值过的用户则不叠加奖池*/
//                            if (tUser.getUserTotalRecharge().compareTo(BigDecimal.ZERO) > 0) {
//                                jackpot = jackpot.add(price.multiply(new BigDecimal(jackpotConfigValue)));
//                            }
//                            List<TGoods> lowList = tGoodsMapper.lowBoxGoodsList(boxId, jackpot.toString());
//                            if (lowList.size() == 0) {
//                                lowList = tGoodsMapper.lowestPriceGoods(boxId);
//                            }
//                            List<GiftDTO> giftDTOList = new ArrayList<>();
//                            for (int i = 0; i < lowList.size(); i++) {
//                                GiftDTO giftDTO = new GiftDTO();
//                                giftDTO.setIndex(i);
//                                giftDTO.setNo(lowList.get(i).getGoodsId().toString());
//                                giftDTO.setName(lowList.get(i).getGoodsName());
//                                giftDTO.setProbability(lowList.get(i).getGoodsChance().doubleValue());
//                                giftDTOList.add(giftDTO);
//                            }
//                            Integer idex = GiftDTO.luckdraw(giftDTOList);
//                            tGoods = lowList.get(idex);
//                            ruleType = Constants.RULE_TYPE0;
//                            tGoods.setRuleType(ruleType);
//                            resultList.add(tGoods);
//                            if (StringUtils.isNotEmpty(tBox.getBoxLevel())) {
//                                if (newUserNum >= boxLevelNum) {
//                                    newUserNum = newUserNum - boxLevelNum;
//                                }
//                            }
//                            /**获取的排名前N的饰品则清空奖池*/
//                            boolean flag = goodsTopN.contains(tGoods.getGoodsId());
//                            if (flag) {
//                                jackpot = tBox.getInitialJackpot();
//                            }
//                        }
//                        if (tGoods != null) {
//                            userTotalAssets = userTotalAssets.subtract(tBox.getBoxPrice()).add(tGoods.getGoodsPrice());
//                        }
//                        dividend = dividend.add(tBox.getBoxPrice().subtract(tGoods.getGoodsPrice()));
//                    }
//                    /*增加销量*/
//                    Long salesVolume = tBox.getSalesVolume() == null ? 0L : tBox.getSalesVolume();
//                    tBox.setSalesVolume(salesVolume + num);
//                    tBox.setJackpot(jackpot);
//                    tBox.setDividend(dividend);
//                }
//            }
//            if (resultList.size() == 0) {
//                return Response.fail(Constants.FAILCODE, "系统繁忙，请稍后重试！");
//            }
//
//            /**根据抽中的数据插入到背包表中*/
//            List<TBackpack> backpackList = new ArrayList<>();
//            /**开启后余额*/
//            BigDecimal openAfterBalance = tUser.getUserBalance();
//            Date time = DateUtils.getNowDate();
//            for (TGoods bean1 : resultList) {
//                TGoods bean = new TGoods();
//                BeanUtils.copyProperties(bean1, bean);
//
//                String bbId = DateUtils.dateTimeNow() + IdUtils.fastUUID().substring(0, 8);
//                /**给返回的饰品列表添加背包ID，以便前台取用*/
//                bean.setBbId(bbId);
//
//                /**插入背包表*/
//                TBackpack backpack = new TBackpack();
//                backpack.setBbId(bbId);
//                backpack.setUserId(userId);
//                backpack.setGoodsId(bean.getGoodsId());
//                backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE0);
//                backpack.setGoodsBelongingId(bean.getGoodsBelongingId());
//                backpack.setGoodsBelongingName(tBox.getBoxName());
//                backpack.setGoodsPrice(bean.getGoodsPrice());
//                backpack.setGoodsExprice(bean.getGoodsExprice());
//                backpack.setDelFlag(Constants.SUCCESS);
//                backpack.setCreateTime(time);
//                backpack.setGoodsType(bean.getGoodsType());
//                backpack.setGoodsNum(1);
//                backpack.setOpenBeforeBalance(openAfterBalance);
//                backpack.setUserPromotersId(tUser.getUserPromotersId());
//                backpack.setOpenBoxPrice(tBox.getBoxPrice());
//                backpack.setAuditStatus(Constants.AUDITSTATUS0);
//                backpack.setRuleType(bean1.getRuleType());
//                backpack.setBbGoodsName(bean.getGoodsName());
//                backpack.setBbGoodsPic(bean.getGoodsPic());
//                backpack.setBbGoodsGrate(bean.getGoodsGrate());
//                /**余额*/
//                openAfterBalance = openAfterBalance.subtract(tBox.getBoxPrice());
//                /**判断是否为金币，如果是金币直接兑换,背包状态修改为已兑换*/
//                backpack.setOpenAfterBalance(openAfterBalance);
//                if (bean.getGoodsType().equals("4")) {
//                    backpack.setBbStatus(Constants.BBSTATUS3);
//                } else {
//                    backpack.setBbStatus(Constants.BBSTATUS0);
//                }
//                backpackList.add(backpack);
//                goodsList.add(bean);
//            }
//            /**批量插入背包信息表*/
//            int row = backpackMapper.insertTBackpackBatch(backpackList);
//            /**余额变更记录表*/
//            TBalanceChange balanceChange = new TBalanceChange();
//            balanceChange.setUserId(userId);
//            balanceChange.setBalanceBefore(balance);
//            balanceChange.setBalanceAfter(openAfterBalance);
//            balanceChange.setOperationType(Constants.OPERATIONTYPE1);
//            balanceChange.setFrequency(num);
//            balanceChange.setFee(balance.subtract(openAfterBalance));
//            balanceChange.setCorrespondingid(boxId);
//            balanceChange.setCreateTime(DateUtils.getNowDate());
//
//            /**修改箱子的奖池*/
//            int jac = tBoxMapper.updateJackpot(tBox);
//            if (jac == 0) {
//                throw new SQLException("网络延迟,请重新抽奖! ");
//            }
//            /*判断用户商城可购买额度*/
//            /*用户余额-购买额度>=花费金额 则不变 否则重置为用户余额-花费金额*/
//            BigDecimal purchaseQuota = tUser.getPurchaseQuota();
//            if (balance.subtract(purchaseQuota).compareTo(price.multiply(new BigDecimal(num))) == -1) {
//                tUser.setPurchaseQuota(openAfterBalance);
//            }
//            /**修改用户的余额*/
//            tUser.setUserBalance(openAfterBalance);
//            tUser.setUpdateTime(time);
//            tUser.setNewUserNum(newUserNum);
//            int row1 = tUserMapper.updateTUserBalance(tUser);
//            if (row1 == 0) {
//                throw new SQLException("网络延迟,请重新抽奖! ");
//            }
//            balanceChangeMapper.insertTBalanceChange(balanceChange);
//            if (lockFlag1) {
//                /**重新设值并设值过期时间*/
//                Calendar c = Calendar.getInstance();
//                c.setTime(new Date());
//                c.add(Calendar.DAY_OF_MONTH, 1);
//                String displayTime = new SimpleDateFormat("yyyy-MM-dd").format(c.getTime()) + " 00:00:00";
//                Long expiretime = DateUtils.getDatePoor1(DateUtils.parseDate(displayTime), DateUtils.getNowDate());
//                if(tBox.getTotalNum() != null){
//                    redisCache.setCacheObject(unpackingBoxIdkey, boxTotalNum, new Long(expiretime).intValue(), TimeUnit.MINUTES);
//                }
//                if(tBox.getSingleUserNum() != null){
//                    redisCache.setCacheObject(SingleOpenBoxKey, boxSingleNum, new Long(expiretime).intValue(), TimeUnit.MINUTES);
//                }
//            }
//            return Response.success(goodsList);
//        } catch (Exception e) {
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            log.error("开箱失败:{}", e.getMessage());
//        } finally {
//            if (lockFlag1) {
//                redisLock.release(lockKey, lockTime);
//            }
//        }
//        return Response.fail("网络延迟,请重试!");
//    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<List<TGoods>> oddNumUnpacking(String userId, String boxId, Integer num) throws Exception {
        if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(boxId) || StringUtils.isNull(num)) {
            return Response.fail(Constants.FAILCODE, "参数不能为空！");
        }
        /**根据用户ID获取用户信息*/
        TUser tUser = tUserMapper.selectTUserById(userId);

        if (tUser == null || !Constants.SUCCESS.equals(tUser.getDelFlag())) {
            return Response.fail(Constants.FAILCODE, "用户不存在或已被冻结，请联系管理员！");
        }

        /**用户余额*/
        BigDecimal balance = tUser.getUserBalance();
        /**充值积分*/
        BigDecimal czIntegral = tUser.getCzIntegral();
        /**推广积分*/
        BigDecimal tgIntegral = tUser.getTgIntegral();

        /**根据箱子ID获取箱子信息*/
        TBox tBox = tBoxMapper.selectTBoxById(boxId);

        /**箱子校验*/
        if (StringUtils.isNull(tBox)) {
            return Response.fail(Constants.FAILCODE, "箱子不存在,请勿重复操作！");
        }
        if (!Constants.SUCCESS.equals(tBox.getDelFlag())) {
            return Response.fail(Constants.FAILCODE, "箱子未上架,请勿重复操作！");
        }

        /**箱子价格*/
        BigDecimal price = tBox.getBoxPrice();
        /**充值积分箱子的兑换比例*/
        BigDecimal subscriptionRatio = tBox.getSubscriptionRatio();

        /**判断是否满足开箱条件*/
        if (Constants.BOXTYPE0.equals(tBox.getBoxType())){
            /**开箱箱子*/
            if (balance.compareTo(price.multiply(new BigDecimal(num))) < 0) {
                return Response.fail(Constants.FAILCODE, "余额不足，请充值后再开箱！");
            }
        }else if (Constants.BOXTYPE2.equals(tBox.getBoxType())){
            price = price.multiply(subscriptionRatio).setScale(2,BigDecimal.ROUND_HALF_UP);
            /**充值积分箱子*/
            if (czIntegral.compareTo(price.multiply(new BigDecimal(num))) < 0) {
                return Response.fail(Constants.FAILCODE, "充值积分不足，请充值后再开箱！");
            }
        }else if (Constants.BOXTYPE3.equals(tBox.getBoxType())){
            /**推广积分箱子*/
            if (tgIntegral.compareTo(price.multiply(new BigDecimal(num))) < 0) {
                return Response.fail(Constants.FAILCODE, "推广积分不足！");
            }
        }else {
            return Response.fail(Constants.FAILCODE, "非正常箱子，请勿重复操作！");
        }

        if (price.compareTo(new BigDecimal("0")) == 0){
            return Response.fail(Constants.FAILCODE, "箱子异常,请联系管理员！");
        }


        String lockTime = DateUtils.getTimeAfter(DateUtils.getNowDate(), 1);
        lockTime = Long.toString(DateUtils.parseDate(lockTime).getTime());
        String lockKey = Constants.OPENBOXKEY + boxId;
        boolean lockFlag1 = false;
        try {
            String unpackingBoxIdkey = Constants.UNPACKINGBOXIDKEY + tBox.getBoxId();
            String SingleOpenBoxKey = Constants.UNPACKINGUSERIDKEY + tUser.getUserId() + ":" + boxId;
            Integer boxTotalNum = 0;
            Integer boxSingleNum = 0;
            if (Constants.BOXTYPE0.equals(tBox.getBoxType()) && (tBox.getTotalNum() != null || tBox.getSingleUserNum() != null)) {
                lockFlag1 = true;
                /**获取锁*/
                boolean lockflag = redisLock.lock(lockKey, lockTime);
                if (!lockflag) {
                    Thread.currentThread().sleep(500);
                    lockflag = redisLock.lock(lockKey, lockTime);
                }
                if (lockflag) {
                    if (tBox.getTotalNum() != null) {
                        /*当日该箱开启总次数*/
                        boxTotalNum = redisCache.getCacheObject(unpackingBoxIdkey) == null ? 0 : redisCache.getCacheObject(unpackingBoxIdkey);
                        boxTotalNum = boxTotalNum + num;
                        if (tBox.getTotalNum() < boxTotalNum) {
                            return Response.fail("无剩余次数！");
                        }
                    }
                    if (tBox.getSingleUserNum() != null) {
                        /*单人当日开启该箱总次数*/
                        boxSingleNum = redisCache.getCacheObject(SingleOpenBoxKey) == null ? 0 : redisCache.getCacheObject(SingleOpenBoxKey);
                        boxSingleNum = boxSingleNum + num;
                        if (tBox.getSingleUserNum() < boxSingleNum) {
                            return Response.fail("无剩余次数！");
                        }
                    }
                } else {
                    log.error("获取开箱锁失败");
                    return Response.fail("网络延迟，请重试！");
                }
            }
            /**抽到的饰品列表*/
            List<TGoods> resultList = new ArrayList<>();
            /**主播用户概率抽奖*/
            if (tUser.getUserType().equals(Constants.USERTYPE1)) {
                /**
                 * 当主播账户余额+背包饰品总价值＜1000时，随机概率50%执行主播保底算法
                 * 若主播选择开箱和对战，则主播开出的饰品都是随机在金、红、紫色品级中出现（即每个饰品的概率为1/金红紫饰品总数）。
                 * 若主播得到饰品后  账户余额+背包饰品总价值≥1000,则主播开箱和对战恢复正常逻辑，若账户余额+背包饰品总价值＜1000，则主播还是走这个保底算法；
                 若主播选择幸运饰品升级，则主播升级成功的概率为主播选择的概率，即不再乘以升级系数，
                 若主播得到饰品后  账户余额+背包饰品总价值≥1000,则主播幸运饰品升级恢复正常逻辑，若账户余额+背包饰品总价值＜1000，则主播还是走这个保底算法*/

                /**查询主播开箱规则参数*/
                /**
                 * 0 主播开箱逻辑为纯概率；
                 * 1 主播开箱逻辑为概率+奖池，但是主播行为不叠加奖池；
                 * 2 主播自定义概率随机开箱。
                 */
                SysConfig ruleTypeConfig = sysConfigMapper.checkConfigKeyUnique("anchor_unpacking_rule_type");
                String ruleType = ruleTypeConfig == null || StringUtils.isEmpty(ruleTypeConfig.getConfigValue()) ? "2" : ruleTypeConfig.getConfigValue();

                SysConfig anchorConfig = sysConfigMapper.checkConfigKeyUnique("anchor_trigger_baodi_quota");
                String anchor_trigger_baodi_quota = anchorConfig == null || StringUtils.isEmpty(anchorConfig.getConfigValue()) ? "1000" : anchorConfig.getConfigValue();

                BigDecimal bbPrice = backpackMapper.countPendingPrice(tUser.getUserId());
                BigDecimal totalfee =  tUser.getUserBalance().add(bbPrice);

                /**如果是推广积分箱子，主播则纯概率开箱*/
                if(Constants.BOXTYPE3.equals(tBox.getBoxType())){
                    ruleType = "0";
                }
                for (int ii=0; ii<num; ii++){
                    TGoods tGoods = null;
                    /**主播是否走保底算法*/
                    boolean flag = false;
                    if(totalfee.compareTo(new BigDecimal(anchor_trigger_baodi_quota)) < 0 && Constants.BOXTYPE0.equals(tBox.getBoxType())){
                        /**随机概率是否走保底*/
                        Random r = new Random();
                        int a  = r.nextInt(2);
                        if(a == 0){
                            flag = true;
                        }
                    }
                    log.info("主播是否走保底概率 主播名:{} 主播总价值:{} 是否走保底概率:{} 主播规则:{},箱子类型:{}",tUser.getUserName(),totalfee,flag,ruleType,tBox.getBoxType());
                    if (flag){
                        /**获取 金 红 紫 饰品*/
                        List<TGoods> list = tGoodsMapper.getBDSFGoods(tBox.getBoxId());
                        Collections.shuffle(list);
                        Random random = new Random();
                        int index = random.nextInt(list.size());
                        tGoods = list.get(index);


                    }else if (Constants.ANCHORUNPACKINGRULE0.equals(ruleType)){
                        /**主播纯概率开箱*/
                        List<TGoods> goodsList = tGoodsMapper.boxGoodsList(Constants.GOOGSBLTYPE0, boxId);
                        List<GiftDTO> giftDTOList = new ArrayList<>();
                        for (int i = 0; i < goodsList.size(); i++) {
                            GiftDTO giftDTO = new GiftDTO();
                            giftDTO.setIndex(i);
                            giftDTO.setNo(goodsList.get(i).getGoodsId().toString());
                            giftDTO.setName(goodsList.get(i).getGoodsName());
                            giftDTO.setProbability(goodsList.get(i).getGoodsChance().doubleValue());
                            giftDTOList.add(giftDTO);
                        }
                        Integer idex = GiftDTO.luckdraw(giftDTOList);
                        tGoods = goodsList.get(idex);
                    }else if (Constants.ANCHORUNPACKINGRULE1.equals(ruleType)){
                        /**主播概率+奖池开箱*/
                        BigDecimal jackpot = tBox.getJackpot() == null ? new BigDecimal(0) : tBox.getJackpot();
                        SysConfig jackpotProportion = sysConfigMapper.checkConfigKeyUnique("jackpot_increase_proportion");
                        String jackpotConfigValue = jackpotProportion.getConfigValue() == null ? "1" : jackpotProportion.getConfigValue();
                        jackpot = jackpot.add(price.multiply(new BigDecimal(jackpotConfigValue)));
                        List<TGoods> lowList = tGoodsMapper.lowBoxGoodsList(tBox.getBoxId(), jackpot.toString());
                        if (lowList.size() == 0) {
                            lowList = tGoodsMapper.lowestPriceGoods(tBox.getBoxId());
                        }

                        List<GiftDTO> giftDTOList = new ArrayList<>();
                        for (int i = 0; i < lowList.size(); i++) {
                            GiftDTO giftDTO = new GiftDTO();
                            giftDTO.setIndex(i);
                            giftDTO.setNo(lowList.get(i).getGoodsId().toString());
                            giftDTO.setName(lowList.get(i).getGoodsName());
                            giftDTO.setProbability(lowList.get(i).getGoodsChance().doubleValue());
                            giftDTOList.add(giftDTO);
                        }
                        Integer idex = GiftDTO.luckdraw(giftDTOList);
                        tGoods = lowList.get(idex);
                    }else {
                        /**主播自定义概率随机开箱*/
                        List<TGoods> highList = tGoodsMapper.highBoxGoodsList(boxId, price.toString());
                        List<TGoods> lowList = tGoodsMapper.lowBoxGoodsList(boxId, price.toString());
                        if (lowList.size() == 0 && highList.size() == 0) {
                            throw new Exception("箱子下不存在饰品！");
                        }
                        if (lowList.size() == 0) {
                            lowList = highList;
                        }
                        if (highList.size() == 0) {
                            highList = lowList;
                        }

                        /*查询出开箱概率*/
                        String hight_price_probability = "0.4";
                        String low_price_probability = "0.6";
                        List<SysDictData> zbOpenboxProbabilityList = sysDictDataMapper.selectDictDataByType("zb_openbox_probability");
                        if (zbOpenboxProbabilityList.size() > 0) {
                            List<SysDictData> hight_price_probability1 = zbOpenboxProbabilityList.stream().filter((SysDictData b) -> b.getDictLabel().equals("hight_price_probability")).collect(Collectors.toList());
                            if (hight_price_probability1.size() > 0) {
                                SysDictData sysDictData = hight_price_probability1.get(0);
                                hight_price_probability = sysDictData == null || StringUtils.isEmpty(sysDictData.getDictValue()) ? "0.4" : sysDictData.getDictValue();
                            }
                            List<SysDictData> low_price_probability1 = zbOpenboxProbabilityList.stream().filter((SysDictData b) -> b.getDictLabel().equals("low_price_probability")).collect(Collectors.toList());
                            if (low_price_probability1.size() > 0) {
                                SysDictData sysDictData = low_price_probability1.get(0);
                                low_price_probability = sysDictData == null || StringUtils.isEmpty(sysDictData.getDictValue()) ? "0.6" : sysDictData.getDictValue();
                            }
                        }

                        /**对箱子进行概率抽奖*/
                        List<GiftDTO> giftDTOList = new ArrayList<>();
                        GiftDTO giftDTO1 = new GiftDTO();
                        giftDTO1.setIndex(0);
                        giftDTO1.setNo("0");
                        giftDTO1.setProbability(Double.parseDouble(hight_price_probability));
                        giftDTOList.add(giftDTO1);

                        GiftDTO giftDTO2 = new GiftDTO();
                        giftDTO2.setIndex(1);
                        giftDTO2.setNo("1");
                        giftDTO2.setProbability(Double.parseDouble(low_price_probability));
                        giftDTOList.add(giftDTO2);

                        int integer = GiftDTO.luckdraw(giftDTOList);
                        if (integer == 0) {
                            List<GiftDTO> giftDTOList1 = new ArrayList<>();
                            for (int i = 0; i < highList.size(); i++) {
                                GiftDTO giftDTO = new GiftDTO();
                                giftDTO.setIndex(i);
                                giftDTO.setNo(highList.get(i).getGoodsId().toString());
                                giftDTO.setName(highList.get(i).getGoodsName());
                                giftDTO.setProbability(highList.get(i).getGoodsChance().doubleValue());
                                giftDTOList1.add(giftDTO);
                            }
                            Integer idex = GiftDTO.luckdraw(giftDTOList1);
                            tGoods = highList.get(idex);
                        } else {
                            List<GiftDTO> giftDTOList2 = new ArrayList<>();
                            for (int i = 0; i < lowList.size(); i++) {
                                GiftDTO giftDTO = new GiftDTO();
                                giftDTO.setIndex(i);
                                giftDTO.setNo(lowList.get(i).getGoodsId().toString());
                                giftDTO.setName(lowList.get(i).getGoodsName());
                                giftDTO.setProbability(lowList.get(i).getGoodsChance().doubleValue());
                                giftDTOList2.add(giftDTO);
                            }
                            Integer idex = GiftDTO.luckdraw(giftDTOList2);
                            tGoods = lowList.get(idex);
                        }
                    }
                    resultList.add(tGoods);
                    /**重新技术主播总价值*/
                    totalfee = totalfee.subtract(price).add(tGoods.getGoodsPrice());
                }
            } else {
                /*利润*/
                BigDecimal dividend = tBox.getDividend() == null ? new BigDecimal(0) : tBox.getDividend();
                /**普通箱子和充值积分箱子*/
                if (Constants.BOXTYPE0.equals(tBox.getBoxType()) || Constants.BOXTYPE2.equals(tBox.getBoxType())){
                    /*设置奖池*/
                    BigDecimal jackpot = tBox.getJackpot() == null ? new BigDecimal(0) : tBox.getJackpot();
                    /*获取箱子中价格前N的商品*/
                    Integer frontJackpotNum = tBox.getFrontJackpotNum() == null ? 5 : tBox.getFrontJackpotNum();
                    List<String> goodsTopN = tGoodsMapper.getGoodsTopN(tBox.getBoxId(), frontJackpotNum);
                    SysConfig jackpotProportion = sysConfigMapper.checkConfigKeyUnique("jackpot_increase_proportion");
                    String jackpotConfigValue = jackpotProportion.getConfigValue() == null ? "1" : jackpotProportion.getConfigValue();
                    for (int j = 0; j < num; j++) {
                        if (tUser.getUserTotalRecharge().compareTo(BigDecimal.ZERO) > 0) {
                            jackpot = jackpot.add(price.multiply(new BigDecimal(jackpotConfigValue)));
                        }
                        List<TGoods> lowList = tGoodsMapper.lowBoxGoodsList(boxId, jackpot.toString());
                        if (lowList.size() == 0) {
                            lowList = tGoodsMapper.lowestPriceGoods(boxId);
                        }
                        List<GiftDTO> giftDTOList = new ArrayList<>();
                        for (int i = 0; i < lowList.size(); i++) {
                            GiftDTO giftDTO = new GiftDTO();
                            giftDTO.setIndex(i);
                            giftDTO.setNo(lowList.get(i).getGoodsId().toString());
                            giftDTO.setName(lowList.get(i).getGoodsName());
                            giftDTO.setProbability(lowList.get(i).getGoodsChance().doubleValue());
                            giftDTOList.add(giftDTO);
                        }
                        Integer idex = GiftDTO.luckdraw(giftDTOList);
                        TGoods tGoods = lowList.get(idex);
                        resultList.add(tGoods);

                        /**获取的排名前N的饰品则清空奖池*/
                        boolean flag = goodsTopN.contains(tGoods.getGoodsId());
                        if (flag) {
                            jackpot = tBox.getInitialJackpot();
                        }
                        dividend = dividend.add(price.subtract(tGoods.getGoodsPrice()));
                    }
                    tBox.setJackpot(jackpot);
                }else {
                    /**推广积分盲盒 纯概率开箱*/
                    /**主播纯概率开箱*/
                    List<TGoods> goodsList = tGoodsMapper.boxGoodsList(Constants.GOOGSBLTYPE0, boxId);
                    List<GiftDTO> giftDTOList = new ArrayList<>();
                    for (int i = 0; i < goodsList.size(); i++) {
                        GiftDTO giftDTO = new GiftDTO();
                        giftDTO.setIndex(i);
                        giftDTO.setNo(goodsList.get(i).getGoodsId().toString());
                        giftDTO.setName(goodsList.get(i).getGoodsName());
                        giftDTO.setProbability(goodsList.get(i).getGoodsChance().doubleValue());
                        giftDTOList.add(giftDTO);
                    }
                    for (int j = 0; j < num; j++) {
                        Integer idex = GiftDTO.luckdraw(giftDTOList);
                        TGoods tGoods = goodsList.get(idex);
                        dividend = dividend.add(price.subtract(tGoods.getGoodsPrice()));
                        resultList.add(tGoods);
                    }
                }
                /**设置利润*/
                tBox.setDividend(dividend);
                /**增加销量*/
                Long salesVolume = tBox.getSalesVolume() == null ? 0L : tBox.getSalesVolume();
                tBox.setSalesVolume(salesVolume + num);

            }

            if (resultList.size() == 0) {
                return Response.fail(Constants.FAILCODE, "系统繁忙，请稍后重试！");
            }

            /**根据抽中的数据插入到背包表中*/
            List<TBackpack> backpackList = new ArrayList<>();
            /**开启后余额*/
            BigDecimal openAfterBalance = tUser.getUserBalance();
            /**开启后充值积分*/
            BigDecimal openAfterCZJF = tUser.getCzIntegral();
            /**开启后推广充值积分*/
            BigDecimal openAfterTGJF = tUser.getTgIntegral();

            Date time = DateUtils.getNowDate();
            List<TGoods> goodsList = new ArrayList<>();
            for (TGoods bean1 : resultList) {
                TGoods bean = new TGoods();
                BeanUtils.copyProperties(bean1, bean);

                String bbId = DateUtils.dateTimeNow() + IdUtils.fastUUID().substring(0, 8);
                /**给返回的饰品列表添加背包ID，以便前台取用*/
                bean.setBbId(bbId);
                /**插入背包表*/
                TBackpack backpack = new TBackpack();
                backpack.setBbId(bbId);
                backpack.setUserId(userId);
                backpack.setGoodsId(bean.getGoodsId());
                if(tBox.getBoxType().equals(Constants.BOXTYPE0)){
                    backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE0);
                }else if (tBox.getBoxType().equals(Constants.BOXTYPE2)) {
                    backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE8);
                }else {
                    backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE9);
                }
                backpack.setGoodsBelongingId(bean.getGoodsBelongingId());
                backpack.setGoodsBelongingName(tBox.getBoxName());
                backpack.setGoodsPrice(bean.getGoodsPrice());
                backpack.setGoodsExprice(bean.getGoodsExprice());
                backpack.setDelFlag(Constants.SUCCESS);
                backpack.setCreateTime(time);
                backpack.setGoodsType(bean.getGoodsType());
                backpack.setGoodsNum(1);
                backpack.setOpenBeforeBalance(openAfterBalance);
                backpack.setUserPromotersId(tUser.getUserPromotersId());
                backpack.setOpenBoxPrice(price);
                backpack.setAuditStatus(Constants.AUDITSTATUS0);
                backpack.setBbGoodsName(bean.getGoodsName());
                backpack.setBbGoodsPic(bean.getGoodsPic());
                backpack.setBbGoodsGrate(bean.getGoodsGrate());
                if (!tUser.getUserType().equals(Constants.USERTYPE1)) {
                    backpack.setRuleType(Constants.RULE_TYPE0);
                }


                if (Constants.BOXTYPE0.equals(tBox.getBoxType())){
                    /**普通箱子开箱 扣除余额*/
                    openAfterBalance = openAfterBalance.subtract(price);
                }else if (Constants.BOXTYPE2.equals(tBox.getBoxType())){
                    /**充值积分箱子 扣除充值积分*/
                    openAfterCZJF = openAfterCZJF.subtract(price);
                }else{
                    openAfterTGJF = openAfterTGJF.subtract(price);
                }

                /**判断是否为金币，如果是金币直接兑换,背包状态修改为已兑换*/
                backpack.setOpenAfterBalance(openAfterBalance);

                backpack.setBbStatus(Constants.BBSTATUS0);
                backpackList.add(backpack);
                goodsList.add(bean);
            }
            /**批量插入背包信息表*/
            int row = backpackMapper.insertTBackpackBatch(backpackList);
            /**余额变更记录表*/
            TBalanceChange balanceChange = new TBalanceChange();
            balanceChange.setUserId(userId);
            balanceChange.setBalanceBefore(balance);
            balanceChange.setBalanceAfter(openAfterBalance);
            balanceChange.setOperationType(Constants.OPERATIONTYPE1);
            balanceChange.setFrequency(num);
            balanceChange.setFee(balance.subtract(openAfterBalance));
            balanceChange.setCorrespondingid(boxId);
            balanceChange.setCreateTime(DateUtils.getNowDate());
            balanceChange.setCzIntegralBefore(czIntegral);
            balanceChange.setCzIntegralAfter(openAfterCZJF);
            balanceChange.setTgIntegralBefore(tgIntegral);
            balanceChange.setTgIntegralAfter(openAfterTGJF);

            /**修改箱子的奖池*/
            int jac = tBoxMapper.updateJackpot(tBox);
            if (jac == 0) {
                throw new SQLException("网络延迟,请重新抽奖! ");
            }
            /*判断用户商城可购买额度*/
            /*用户余额-购买额度<花费金额 则重置为用户余额-花费金额*/
            BigDecimal purchaseQuota = tUser.getPurchaseQuota();
            if (Constants.BOXTYPE0.equals(tBox.getBoxType()) && balance.subtract(purchaseQuota).compareTo(price.multiply(new BigDecimal(num))) == -1) {
                tUser.setPurchaseQuota(openAfterBalance);
            }
            /**修改用户的余额*/
            tUser.setUserBalance(openAfterBalance);
            tUser.setCzIntegral(openAfterCZJF);
            tUser.setTgIntegral(openAfterTGJF);
            tUser.setUpdateTime(time);
            int row1 = tUserMapper.updateTUserBalance(tUser);
            if (row1 == 0) {
                throw new SQLException("网络延迟,请重新抽奖! ");
            }
            balanceChangeMapper.insertTBalanceChange(balanceChange);
            if (lockFlag1){
                /**重新设值并设值过期时间*/
                Calendar c = Calendar.getInstance();
                c.setTime(new Date());
                c.add(Calendar.DAY_OF_MONTH, 1);
                String displayTime = new SimpleDateFormat("yyyy-MM-dd").format(c.getTime()) + " 00:00:00";
                Long expiretime = DateUtils.getDatePoor1(DateUtils.parseDate(displayTime), DateUtils.getNowDate());
                if(tBox.getTotalNum() != null){
                    redisCache.setCacheObject(unpackingBoxIdkey, boxTotalNum, new Long(expiretime).intValue(), TimeUnit.MINUTES);
                }
                if(tBox.getSingleUserNum() != null){
                    redisCache.setCacheObject(SingleOpenBoxKey, boxSingleNum, new Long(expiretime).intValue(), TimeUnit.MINUTES);
                }
            }
            return Response.success(goodsList);
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("开箱失败:{}", e.getMessage());
        } finally {
            if(lockFlag1){
                redisLock.release(lockKey, lockTime);
            }
        }
        return Response.fail("网络延迟，请重试！");
    }

    @Override
    public List<TGoods> openBoxRule(List<TGoods> tGoodsList,String boxId,int cs){
//        /**获取对应箱子下的饰品列表*/
//        List<TGoods> tGoodsList = this.goodsListByBoxId(boxId);
//        if (tGoodsList == null || tGoodsList.size() == 0) {
//            return new AjaxResult(Constants.FAILCODE,"箱子下不存在饰品！");
//        }
        List<TGoods> resultTGoods = new ArrayList<>();

        String lockTime = DateUtils.getTimeAfter(DateUtils.getNowDate(),1);
        lockTime = Long.toString(DateUtils.parseDate(lockTime).getTime());
        String lockKey = Constants.OPENKEY+boxId;
        String boxIdKey = Constants.BOXIDKEY+boxId;
        //redisCache.setCacheMap(boxIdKey,new HashMap<>());
        try {
            /**获取锁*/
            boolean lockflag = redisLock.lock(lockKey,lockTime);
            if (!lockflag) {
                Thread.currentThread().sleep(1000);
                lockflag = redisLock.lock(lockKey,lockTime);
            }
            if (lockflag){
                /**获取该箱子中还存在多少饰品可以开取*/
                Map<String, Integer> redismap = redisCache.getCacheMap(boxIdKey);
                if (StringUtils.isEmpty(redismap)) {
                    /**初始化*/
                    redisCache.setCacheMap(boxIdKey,new HashMap<>());
                    redismap = redisCache.getCacheMap(boxIdKey);
                }

                for (int a=0;a<cs;a++){
                    /**所有可以开箱的饰品集合*/
                    List<TGoods> allGoodsList = new ArrayList<>();
                    for (TGoods tGoods : tGoodsList) {
                        int num = tGoods.getGoodsChance().multiply(new BigDecimal(10000)).intValue();
                        String goodsId = tGoods.getGoodsId();
                        Integer count = redismap.get(goodsId) == null ? 0 : redismap.get(goodsId);
                        num = num-count;
                        for (int i=0;i<num;i++){
                            TGoods cp = new TGoods();
                            BeanUtils.copyProperties(tGoods,cp);
                            allGoodsList.add(cp);
                        }
                    }
                    /**说明箱子中的饰品已全部开完，重置*/
                    if (allGoodsList.size() == 0) {
                        for (TGoods tGoods : tGoodsList) {
                            int num = tGoods.getGoodsChance().multiply(new BigDecimal(10000)).intValue();
                            for (int i=0;i<num;i++){
                                TGoods cp = new TGoods();
                                BeanUtils.copyProperties(tGoods,cp);
                                allGoodsList.add(cp);
                            }
                        }
                        /**重置箱子的KEY*/
                        redismap = new HashMap<>();
                        redisCache.deleteObject(boxIdKey);
                    }

                    /**随机抽奖*/
                    Random random = new Random();
                    int index = random.nextInt(allGoodsList.size());
                    TGoods zjTgoods = allGoodsList.get(index);
                    /**添加到*/
                    resultTGoods.add(zjTgoods);

                    Integer count = redismap.get(zjTgoods.getGoodsId()) == null ? 0 : redismap.get(zjTgoods.getGoodsId());
                    ++count;
                    redismap.put(zjTgoods.getGoodsId(),count);

                    log.info("开箱后redis中箱子ID：{},随机数:{},开出的饰品名称:{}，开出饰品的价值:{}", boxId,index,zjTgoods.getGoodsName(),zjTgoods.getGoodsPrice());
                }
                redisCache.setCacheMap(boxIdKey,redismap);
                log.info("开箱后redis中箱子ID：{},饰品开出的详情:{}", boxId,JSON.toJSONString(redismap));


                int count = 0;
                for (String key : redismap.keySet()) {
                    count = count + redismap.get(key).intValue();
                }
                log.info("开箱后redis中箱子ID：{},总共开箱次数：{}}", boxId,count);
            }else {
                log.error("获取开箱锁失败");
            }
        }catch (Exception e){
            log.error("开箱异常：{}",e.getMessage());
        }finally {
            redisLock.release(lockKey,lockTime);
        }
        return resultTGoods;
    }

    @Override
    public Response<Map> openBoxRuleTest(String boxId,int cs){
        if (cs > 1000) {
            return Response.fail(Constants.FAILCODE,"测试开启数量至多1000！");
        }
        /**获取对应箱子下的饰品列表*/
        List<TGoods> tGoodsList = this.goodsListByBoxId(boxId);
        if (tGoodsList == null || tGoodsList.size() == 0) {
            return Response.fail(Constants.FAILCODE,"箱子下不存在饰品！");
        }
        List<TGoods> resultTGoods = new ArrayList<>();

        String lockTime = DateUtils.getTimeAfter(DateUtils.getNowDate(),2);
        lockTime = Long.toString(DateUtils.parseDate(lockTime).getTime());
        String lockKey = Constants.OPENKEY+boxId;
        String boxIdKey = Constants.BOXIDKEY+boxId;
        Map result = new HashMap();
        try {
            /**获取锁*/
            boolean lockflag = redisLock.lock(lockKey,lockTime);
            if (!lockflag) {
                Thread.currentThread().sleep(1000);
                lockflag = redisLock.lock(lockKey,lockTime);
            }
            if (lockflag){
                /**获取该箱子中还存在多少饰品可以开取*/
                Map<String, Integer> redismap = redisCache.getCacheMap(boxIdKey);
                if (StringUtils.isEmpty(redismap)) {
                    /**初始化*/
                    redisCache.setCacheMap(boxIdKey,new HashMap<>());
                    redismap = redisCache.getCacheMap(boxIdKey);
                }

                for (int a=0;a<cs;a++){
                    /**所有可以开箱的饰品集合*/
                    List<TGoods> allGoodsList = new ArrayList<>();
                    for (TGoods tGoods : tGoodsList) {
                        int num = tGoods.getGoodsChance().multiply(new BigDecimal(10000)).intValue();
                        String goodsId = tGoods.getGoodsId();
                        Integer count = redismap.get(goodsId) == null ? 0 : redismap.get(goodsId);
                        num = num-count;
                        for (int i=0;i<num;i++){
                            TGoods cp = new TGoods();
                            BeanUtils.copyProperties(tGoods,cp);
                            allGoodsList.add(cp);
                        }
                    }
                    /**说明箱子中的饰品已全部开完，重置*/
                    if (allGoodsList.size() == 0) {
                        for (TGoods tGoods : tGoodsList) {
                            int num = tGoods.getGoodsChance().multiply(new BigDecimal(10000)).intValue();
                            for (int i=0;i<num;i++){
                                TGoods cp = new TGoods();
                                BeanUtils.copyProperties(tGoods,cp);
                                allGoodsList.add(cp);
                            }
                        }
                        /**重置箱子的KEY*/
                        redismap = new HashMap<>();
                        redisCache.deleteObject(boxIdKey);
                    }

                    /**随机抽奖*/
                    Random random = new Random();
                    int index = random.nextInt(allGoodsList.size());
                    TGoods zjTgoods = allGoodsList.get(index);
                    /**添加到*/
                    resultTGoods.add(zjTgoods);

                    Integer count = redismap.get(zjTgoods.getGoodsId()) == null ? 0 : redismap.get(zjTgoods.getGoodsId());
                    ++count;
                    redismap.put(zjTgoods.getGoodsId(),count);
                }
                redisCache.setCacheMap(boxIdKey,redismap);

                result.put("redismap",JSON.toJSONString(redismap));
                log.info("开箱后redis中箱子ID：{},饰品已开出的详情统计:{}", boxId,JSON.toJSONString(redismap));

                int count = 0;
                for (String key : redismap.keySet()) {
                    count = count + redismap.get(key).intValue();
                }
                log.info("开箱后redis中箱子ID：{},总共开箱次数：{}}", boxId,count);
                result.put("countTotal",count);
            }else {
                log.error("获取开箱锁失败");
            }
        }catch (Exception e){
            log.error("开箱异常：{}",e.getMessage());
        }finally {
            redisLock.release(lockKey,lockTime);
        }
        Map<String, Long> countMap  = resultTGoods.stream().collect(Collectors.groupingBy(TGoods::getGoodsId,Collectors.counting()));
        result.put("countMap",JSON.toJSONString(countMap));
        //result.put("resultgoods",resultTGoods);
        return Response.success(result);
    }

//    @Override
//    public Response<Map> getList() {
//        Map map = new HashMap();
//        try {
//            /**箱子标题下的箱子列表*/
//            TBoxTitle tBoxTitle = new TBoxTitle();
//            tBoxTitle.setDelFlag(Constants.SUCCESS);
//            List<TBoxTitle> boxTitleList = titleService.selectTBoxTitleList(tBoxTitle);
//            List<String> boxTitleIdList  = boxTitleList.stream().map(TBoxTitle::getBoxtitleId).collect(Collectors.toList());
//            /*响应数据*/
//            List<TBoxTitleVo> tBoxTitleListResponse = new ArrayList<>();
//            List<TBox> tBoxList = tBoxMapper.selectTBoxListAndGoodsPicNew(boxTitleIdList);
//            if(boxTitleIdList.size()>0){
//                /*遍历过滤箱子列表*/
//                boxTitleList.stream().forEach(boxTitle->{
//                    TBoxTitleVo tBoxTitleVo = new TBoxTitleVo();
//                    BeanUtils.copyProperties(boxTitle, tBoxTitleVo);
//                    /*根据标题id过滤*/
//                    List<TBox> filterTboxList = tBoxList.stream().filter(
//                                    (TBox b) -> b.getBoxtitleId().equals(boxTitle.getBoxtitleId())).
//                            collect(Collectors.toList());
//
//                    /*去重*/
//                    if(filterTboxList.size()>0){
//                        List<TBox> list = filterTboxList.stream().collect(
//                                Collectors.collectingAndThen(
//                                        Collectors.toCollection(
//                                                () -> new TreeSet<>(Comparator.comparing(box -> box.getBoxId()))
//                                        ),
//                                        ArrayList::new
//                                )
//                        );
//
//                        list = list.stream().sorted(Comparator.comparing(TBox::getSort))
//                                .collect(Collectors.toList());
//
//                        tBoxTitleVo.setTBoxList(list);
//                        if (list.size() != 0) {
//                            tBoxTitleListResponse.add(tBoxTitleVo);
//                        }
//                    }
//                });
//            }
//            map.put("tBoxTitleList", tBoxTitleListResponse);
//        } catch (Exception e) {
//            log.error("查询盲盒列表异常:{}", e.getMessage());
//            Response.fail("查询盲盒列表异常");
//        }
//        return Response.success(map);
//    }

    @Override
    public Response<Map> getList() {
        Map map = new HashMap();
        try {
            /**箱子标题下的箱子列表*/
            TBoxTitle tBoxTitle = new TBoxTitle();
            tBoxTitle.setDelFlag(Constants.SUCCESS);
            List<TBoxTitle> boxTitleList = titleService.selectTBoxTitleList(tBoxTitle);
            List<String> boxTitleIdList  = boxTitleList.stream().map(TBoxTitle::getBoxtitleId).collect(Collectors.toList());
            /*响应数据*/
            List<TBoxTitleVo> tBoxTitleListResponse = new ArrayList<>();
            List<TBox> tBoxList = tBoxMapper.selectHomeBoxList(boxTitleIdList);
            if(boxTitleIdList.size()>0){
                /*遍历过滤箱子列表*/
                boxTitleList.stream().forEach(boxTitle->{
                    TBoxTitleVo tBoxTitleVo = new TBoxTitleVo();
                    BeanUtils.copyProperties(boxTitle, tBoxTitleVo);
                    /*根据标题id过滤*/
                    List<TBox> filterTboxList = tBoxList.stream().filter(
                            (TBox b) -> b.getBoxtitleId().equals(boxTitle.getBoxtitleId())).
                            collect(Collectors.toList());
                    tBoxTitleVo.setTBoxList(filterTboxList);
                    if(CollectionUtil.isNotEmpty(filterTboxList)){
                        tBoxTitleListResponse.add(tBoxTitleVo);
                    }
                });
            }
            map.put("tBoxTitleList", tBoxTitleListResponse);
        } catch (Exception e) {
            log.error("查询盲盒列表异常:{}", e.getMessage());
            Response.fail("查询盲盒列表异常");
        }
        return Response.success(map);
    }


    /**
     * 箱子后台管理列表
     * @param tBoxVo
     * @return
     */
    @Override
    public List<TBoxVo> boxListBack(TBoxVo tBoxVo) {
        List<TBoxVo> list = new ArrayList<>();
        long start = System.currentTimeMillis();
        if(StringUtils.isNotEmpty(tBoxVo.getBoxType()) && tBoxVo.getBoxType().equals(Constants.BOXTYPE1)){
            list = tBoxMapper.battleBoxListBack(tBoxVo);
        }else {
            list = tBoxMapper.boxListBack(tBoxVo);
        }
        long end1 = System.currentTimeMillis();
        log.info("查询出箱子信息列表：时间:{} 毫秒",(end1-start));
        if (list!= null && list.size()>0) {
            for (TBoxVo boxVo : list) {
                List<TGoods> goodsList = tGoodsMapper.boxGoodsList("0",boxVo.getBoxId());
                if (goodsList.size()>0){
                    /**封面饰品图设置*/
                    boxVo.setCoverGoodsPic(goodsList.get(0).getGoodsPic());

                    /**推荐箱子标价价格*/
                    BigDecimal recommendPrice = new BigDecimal(0);
                    for (TGoods tGoods : goodsList) {
                        recommendPrice = recommendPrice.add(tGoods.getGoodsPrice().multiply(tGoods.getGoodsChance()));

                        if("1".equals(tGoods.getGoodsStockStatus())){
                            boxVo.setGoodsStockStatus("1");
                        }
                    }
                    /*recommendPrice = recommendPrice.multiply(new BigDecimal(1.1)).setScale(2,BigDecimal.ROUND_HALF_UP);*/
                    boxVo.setRecommendPrice(recommendPrice.setScale(2,BigDecimal.ROUND_HALF_UP));
                }
            }
            long end2 = System.currentTimeMillis();
            log.info("查询出箱子信息列表1：时间:{} 毫秒",(end2-start));

        }
        return list;
    }

    /**
     * 开箱统计
     * @return
     */
    @Override
    public Response<Map> unpackingCount() {
        Map<String, String> map = backpackMapper.unpackingCountTotal();
        String time = DateUtils.getDate()+" 00:00:00";
        Map<String, String> map1 = backpackMapper.unpackingCountToday(time);
        if (map1 != null){
            map.putAll(map1);
        }
        return Response.success(map);
    }

    @Override
    public List<TBoxVo> boxListBackCount(TBoxVo tBoxVo) {
        return tBoxMapper.boxListBackCount(tBoxVo);
    }

    @Override
    public int updateTBoxFirstStatus(TBox tBox) {
        tBox.setUpdateTime(DateUtils.getNowDate());
        return tBoxMapper.updateTBox(tBox);
    }

    @Override
    public Map<String, BigDecimal> boxCount(String startTime, String endTime, String boxType) {
        Map<String, BigDecimal> map = new HashMap<>();
        Map<String, BigDecimal> map1 = new HashMap<>();
        if (boxType.equals(Constants.BOXTYPE0)) {
            map = backpackMapper.boxCountTotal(startTime, endTime, boxType);
            map1 = backpackMapper.boxCountToday(boxType);
        } else {
            map = backpackMapper.battleBoxCountTotal(startTime, endTime);
            map1 = backpackMapper.battleBoxCountToday();
        }
        map.putAll(map1);
        return map;
    }

    @Override
    public List<TGoods> GoodsListBox(String boxId) {
        List<TGoods> list = tGoodsMapper.boxGoodsListBack1("0",boxId);
        if (StringUtils.isNotNull(list) && list.size()>0) {
            for (TGoods tGoods : list) {
                /**饰品开出、取回个数统计*/
                Map<String,Object> map = backpackMapper.goodsOutNumCount(tGoods.getGoodsId());
                tGoods.setOutNum(map.get("outNum").toString());
                tGoods.setRetrieveNum(map.get("retrieveNum").toString());
            }
        }
        return list;
    }

    /**
     * 机器人开箱操作
     *
     * @param userId
     * @param boxId
     * @param num
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<List<TGoods>> robotUnpacking(String userId, String boxId, Integer num) throws Exception {
        if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(boxId) || StringUtils.isNull(num)) {
            return Response.fail(Constants.FAILCODE, "用户ID,箱子ID,开箱数量不能为空！");
        }
        /**根据用户ID获取用户信息*/
        TUser tUser = tUserMapper.selectTUserById(userId);

        if (tUser == null || !Constants.SUCCESS.equals(tUser.getDelFlag())) {
            return Response.fail(Constants.FAILCODE, "用户不存在或已被冻结，请联系管理员！");
        }
        if (!tUser.getUserType().equals(Constants.USERTYPE2)) {
            return Response.fail(Constants.FAILCODE, "开箱异常，请稍后重试！");
        }
        /**根据箱子ID获取箱子信息*/
        TBox tBox = tBoxMapper.selectTBoxById(boxId);
        if (StringUtils.isNull(tBox)) {
            return Response.fail(Constants.FAILCODE, "箱子不存在,请勿重复操作！");
        }
        if (!Constants.SUCCESS.equals(tBox.getDelFlag())) {
            return Response.fail(Constants.FAILCODE, "箱子未上架,请勿重复操作！");
        }
        /**箱子价格*/
        BigDecimal price = tBox.getBoxPrice();
        /**抽到的饰品列表*/
        List<TGoods> resultList = new ArrayList<>();
        if (num > 0) {
            for (int j = 0; j < num; j++) {
                List<TGoods> goodsList = tGoodsMapper.boxGoodsList(Constants.GOOGSBLTYPE0, boxId);
                List<GiftDTO> giftDTOList = new ArrayList<>();
                for (int i = 0; i < goodsList.size(); i++) {
                    GiftDTO giftDTO = new GiftDTO();
                    giftDTO.setIndex(i);
                    giftDTO.setNo(goodsList.get(i).getGoodsId().toString());
                    giftDTO.setName(goodsList.get(i).getGoodsName());
                    giftDTO.setProbability(goodsList.get(i).getGoodsChance().doubleValue());
                    giftDTOList.add(giftDTO);
                }
                Integer idex = GiftDTO.luckdraw(giftDTOList);
                TGoods tGoods = goodsList.get(idex);
                resultList.add(tGoods);
            }
        }
        if (resultList.size() == 0) {
            return Response.fail(Constants.FAILCODE, "系统繁忙，请稍后重试！");
        }
        /**根据抽中的数据插入到背包表中*/
        List<TBackpack> backpackList = new ArrayList<>();
        Date time = DateUtils.getNowDate();
        List<TGoods> goodsList = new ArrayList<>();
        for (TGoods bean1 : resultList) {
            TGoods bean = new TGoods();
            BeanUtils.copyProperties(bean1, bean);
            String bbId = DateUtils.dateTimeNow() + IdUtils.fastUUID().substring(0, 8);
            /**给返回的饰品列表添加背包ID，以便前台取用*/
            bean.setBbId(bbId);
            /**插入背包表*/
            TBackpack backpack = new TBackpack();
            backpack.setBbId(bbId);
            backpack.setUserId(userId);
            backpack.setGoodsId(bean.getGoodsId());
            if(Constants.BOXTYPE0.equals(tBox.getBoxType())){
                backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE0);
            }else if(Constants.BOXTYPE2.equals(tBox.getBoxType())){
                backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE8);
            }else {
                backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE9);
            }
            backpack.setGoodsBelongingId(bean.getGoodsBelongingId());
            backpack.setGoodsPrice(bean.getGoodsPrice());
            backpack.setGoodsExprice(bean.getGoodsExprice());
            backpack.setDelFlag(Constants.SUCCESS);
            backpack.setCreateTime(time);
            backpack.setGoodsType(bean.getGoodsType());
            backpack.setGoodsNum(1);
            backpack.setOpenBeforeBalance(new BigDecimal(0));
            backpack.setUserPromotersId(tUser.getUserPromotersId());
            backpack.setOpenBoxPrice(new BigDecimal(0));
            backpack.setAuditStatus(Constants.AUDITSTATUS0);
            backpack.setOpenAfterBalance(new BigDecimal(0));
            backpack.setBbStatus(Constants.BBSTATUS0);
            backpack.setGoodsBelongingName(tBox.getBoxName());
            backpack.setBbGoodsName(bean1.getGoodsName());
            backpack.setBbGoodsPic(bean1.getGoodsPic());
            backpack.setBbGoodsGrate(bean1.getGoodsGrate());
            backpackList.add(backpack);
            goodsList.add(bean);
        }
        backpackMapper.insertTBackpackBatch(backpackList);
        return Response.success(goodsList);
    }

    @Override
    @Transactional
    public Response copyBox(List<String> boxIds) {
        /*根据箱子id查询出箱子下的饰品*/
        /*List<TGoods> goodsList = tGoodsMapper.selectboxGoodsList(boxIds);*/
        /*查询出箱子列表*/
        /*新增箱子*/
        String oldBelongingId = null;
        try {
            List<TBox> boxList = tBoxMapper.selectTBoxListByIds(boxIds);
            /*根据名称查询出箱子数量*/
            if(boxList.size()<0){
                return Response.fail("未查询到您要复制的箱子信息，请重试");
            }
            List<String> boxNames = boxList.stream().map(TBox::getBoxName).collect(Collectors.toList());
            List<String> boxListByNames = tBoxMapper.selectTBoxListByNames(boxNames);
            if(boxListByNames.size()>0){
                return Response.fail(StringUtils.join(boxListByNames,",")+"已存在，不能重复复制");
            }
            for (TBox tBox : boxList) {
                oldBelongingId = tBox.getBoxId();
                if (tBox != null) {
                    tBox.setBoxId(null);
                    tBox.setBoxtitleId(null);
                    tBox.setJackpot(new BigDecimal(0));
                    tBox.setBattleJackpot(new BigDecimal(0));
                    tBox.setVersion(null);
                    tBox.setCreateTime(DateUtils.getNowDate());
                    tBox.setUpdateTime(null);
                    tBox.setBoxType(Constants.BOXTYPE1);
                    tBox.setDelFlag(Constants.STOP);
                    tBox.setBoxLevel(null);
                    int i = tBoxMapper.insertTBox(tBox);
                    if (i > 0) {
                        int i1 = tGoodsMapper.copyBoxTGoods(tBox.getBoxId(), oldBelongingId);
                    }
                }
            }
            return Response.success();
        }catch (Exception e){
            return Response.fail(e.getMessage());
        }
    }

    @Override
    public List<TBox> getBattleBoxList(String type, String boxTitleId,String sortBy) {
        List<TBox> tBoxList = new ArrayList<>();
        try {
            List<String> boxTitleIds = new ArrayList<>();
            if (StringUtils.isNotEmpty(boxTitleId)) {
                boxTitleIds.add(boxTitleId);
            }
            tBoxList = tBoxMapper.selectTBoxListAndGoodsPic(boxTitleIds,type,sortBy);
        } catch (Exception e) {
            log.error("查询盲盒列表异常:{}", e.getMessage());
            Response.fail("查询盲盒列表异常");
        }
        return tBoxList;
    }

    /**
     * 新用户开奖操作
     *
     * @param tBox 箱子信息
     * @param userTotalAssets 用户总资产
     * @param tUser 用户信息
     * @return
     */
    private TGoods newUserDraw(TBox tBox, BigDecimal userTotalAssets, TUser tUser) {
        /*最小金额 = 2-总资产   最大金额区间 = 1.5*首充金额+1-总资产*/
        BigDecimal minInterval = new BigDecimal(2).subtract(userTotalAssets);
        //BigDecimal maxInterval = new BigDecimal(1.5).multiply(tUser.getUserTotalRecharge()).add(new BigDecimal(1)).subtract(userTotalAssets);
        String maxInterval = null;
        /*新用户规则保底上限*/
        SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("new_user_open_box_max_limit");
        if(sysConfig != null){
            maxInterval = StringUtils.isEmpty(sysConfig.getConfigValue()) ? "6.5" : sysConfig.getConfigValue();
        }
        List<TGoods> priceRangeGoods = tGoodsMapper.selectPriceRangeGoods(minInterval.toString(), maxInterval.toString(), tBox.getBoxId(), Constants.GOOGSBLTYPE0);
        TGoods tGoods = new TGoods();
        if (priceRangeGoods.size() > 0) {
            log.info("存在新用户总资产区间饰品最小区间：{},最大区间：{},箱子ID：{}",minInterval,maxInterval,tBox.getBoxId());
            Collections.shuffle(priceRangeGoods);
            Random r = new Random();
            int i = r.nextInt(priceRangeGoods.size());
            tGoods = priceRangeGoods.get(i);
        } else {
            log.info("不存在新用户总资产区间饰品,开出2-总资产:{},箱子ID：{}",minInterval,tBox.getBoxId());
            /*查询出大于 最小金额 = 2*箱子价格-总资产*/
            tGoods = tGoodsMapper.selectLessThanPriceGoods(minInterval.toString(), tBox.getBoxId());
        }
        return tGoods;
    }


    /**
     * 推广盲盒和积分盲盒列表
     * @param type 0 开箱  1 对战
     * @param boxTitleId
     * @param sortBy
     * @return
     */
    @Override
    public List<TBox> activityBoxList(String type) {
        List<TBox> tBoxList  = new ArrayList<>();
        try {
            tBoxList  = tBoxMapper.selectTBoxListAndGoodsPic(null,type,null);
            /*去重*/
            if (tBoxList.size() > 0) {
                tBoxList.stream().forEach(bean -> {
                    if (Constants.BOXTYPE2.equals(bean.getBoxType())){
                        bean.setBoxPrice(bean.getBoxPrice().multiply(bean.getSubscriptionRatio()).setScale(2,BigDecimal.ROUND_HALF_UP));
                    }
                });
                /**去重*/
                tBoxList = tBoxList.stream().collect(
                        Collectors.collectingAndThen(
                                Collectors.toCollection(
                                        () -> new TreeSet<>(Comparator.comparing(box -> box.getBoxId()))
                                ),
                                ArrayList::new
                        )
                );

                /**排序*/
                tBoxList = tBoxList.stream().sorted(Comparator.comparing(TBox::getSort))
                        .collect(Collectors.toList());
            }
        } catch (Exception e) {
            log.error("查询盲盒列表异常:{}", e.getMessage());
            Response.fail("查询盲盒列表异常");
        }
        return tBoxList;
    }

    /**
     * @Desc: 使用hash算法开箱
     * @author: zz
     * @date: 2023/12/6
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<List<TGoods>> openBoxHash(String userId, String boxId, Integer num){
        /**根据用户ID获取用户信息*/
        TUser tUser = tUserMapper.selectTUserById(userId);

        if (tUser == null || !Constants.SUCCESS.equals(tUser.getDelFlag())) {
            return Response.fail(Constants.FAILCODE, "用户不存在或已被冻结，请联系管理员！");
        }
        /**用户余额*/
        BigDecimal balance = tUser.getUserBalance();
        /**第二套货币*/
        BigDecimal secondCurrency = tUser.getSecondCurrency();
        /**根据箱子ID获取箱子信息*/
        TBox tBox = tBoxMapper.selectTBoxById(boxId);
        /**箱子校验*/
        if (StringUtils.isNull(tBox) || !Constants.SUCCESS.equals(tBox.getDelFlag())) {
            return Response.fail(Constants.FAILCODE, "箱子不存在或未上架,请勿重复操作！");
        }
        if(!Constants.BOXTYPE4.equals(tBox.getBoxType()) && (num < 1 || num > 5)){
            return Response.fail("开启数量不合理");
        }

        /**箱子价格*/
        BigDecimal price = tBox.getBoxPrice();
        /**刮刮乐箱子 最低开启次数*/
        Integer gglNum = tBox.getGglNum();
        /**免费箱子 每日充值门槛*/
        BigDecimal everyRecharge = tBox.getEveryRecharge();

        TWarReceive tWarReceive = null;
        /**用户可消费金额*/
        BigDecimal consumableFee = balance.add(secondCurrency);
        /**判断是否满足开箱条件*/
        if (Constants.BOXTYPE0.equals(tBox.getBoxType())){
            /**开箱箱子*/
            if (consumableFee.compareTo(price.multiply(new BigDecimal(num))) < 0) {
                return Response.fail(Constants.FAILCODE, "余额不足，请充值后再开箱！");
            }
            if (price.compareTo(new BigDecimal("0")) == 0){
                return Response.fail(Constants.FAILCODE, "箱子异常,请联系管理员！");
            }

        } else if (Constants.BOXTYPE4.equals(tBox.getBoxType())){
            SysConfig scratchConfig = sysConfigMapper.checkConfigKeyUnique("scratch_card_limit_open_times");
            /**刮刮乐箱子*/
            if(num < tBox.getGglNum() || num > Integer.parseInt(scratchConfig.getConfigValue())){
                return Response.fail(Constants.FAILCODE, "刮刮乐箱子，最低"+tBox.getGglNum()+"起开,最高限制"+scratchConfig.getConfigValue()+"开！");
            }
            if (consumableFee.compareTo(price.multiply(new BigDecimal(num))) < 0) {
                return Response.fail(Constants.FAILCODE, "余额不足，请充值后再开箱！");
            }
            if (price.compareTo(new BigDecimal("0")) == 0){
                return Response.fail(Constants.FAILCODE, "箱子异常,请联系管理员！");
            }

        } else if (Constants.BOXTYPE5.equals(tBox.getBoxType())){
            /**免费箱子*/
            if(num > 1){
                return Response.fail(Constants.FAILCODE, "免费箱子只限单次开启！");
            }
            BigDecimal todayCzMoney = tRechargeMapper.selectTheDayCzCountByUserId(userId);
            if(everyRecharge.compareTo(todayCzMoney) > 0){
                return Response.fail(Constants.FAILCODE, "不符合领取条件！");
            }

            long opennum = backpackMapper.countErveryNum(Constants.GOOGSBLTYPE13,tBox.getBoxId());
            if(opennum > 0){
                return Response.fail(Constants.FAILCODE, "当日已开启，请明天再来！");
            }
        }else if (Constants.BOXTYPE6.equals(tBox.getBoxType())){
            /**战令箱子*/
            if(num > 1){
                return Response.fail(Constants.FAILCODE, "战令箱子只限单次开启！");
            }
            tWarReceive = tWarReceiveMapper.getTWarBox(userId,boxId);
            if(tWarReceive == null){
                return Response.fail(Constants.FAILCODE, "无战令箱子开启！");
            }
            tWarReceive.setUseStatus(1);
        } else {
            return Response.fail(Constants.FAILCODE, "非正常箱子，请勿重复操作！");
        }
        /**抽到的饰品列表*/
        List<TGoods> resultList = new ArrayList<>();
        List<TGoods> goodsList = tGoodsMapper.boxGoodsList(Constants.GOOGSBLTYPE0, boxId);
        if (goodsList.size() == 0) {
                return Response.fail(Constants.FAILCODE, "箱子饰品为空，请联系管理员！");
        }
        /**hash算法进行开箱*/
        String userSeed = tUser.getUserSeed();//客户端种子

        Map<String, String> goodsIdMap = goodsList.stream().collect(Collectors.toMap(TGoods::getGoodsId,TGoods::getRollValueRange));
        Map<String, TGoods> goodsMap = goodsList.stream().collect(Collectors.toMap(TGoods::getGoodsId,t -> t));

        /**开启后余额*/
        BigDecimal openAfterBalance = tUser.getUserBalance();
        /**开启后货币余额*/
        BigDecimal openAfterSecondCurrency = tUser.getSecondCurrency();
        /**根据抽中的数据插入到背包表中*/
        List<TBackpack> backpackList = new ArrayList<>();
        for(int i=0;i<num;i++){
            /**服务端种子*/
            String serverSeed = HashUtil.generateServerSeed();
            /**随机整数*/
            int nonce = HashUtil.generateNonce();
            /**公共hash*/
            String commonHash = HashUtil.commonHashCode(userSeed,serverSeed,nonce);
            /**roll值*/
            Long rollValue = HashUtil.rollValue(commonHash);

            String goodsId = RollValueUtil.rollItem(rollValue.intValue(),goodsIdMap);
            TGoods bean1 = goodsMap.get(goodsId);

            TGoods bean = new TGoods();
            BeanUtils.copyProperties(bean1, bean);

            String bbId = DateUtils.dateTimeNow() + IdUtils.fastUUID().substring(0, 8);
            /**给返回的饰品列表添加背包ID，以便前台取用*/
            bean.setBbId(bbId);
            /**插入背包表*/
            TBackpack backpack = new TBackpack();
            backpack.setBbId(bbId);
            backpack.setUserId(userId);
            backpack.setGoodsId(bean.getGoodsId());
//            backpack.setOpenBeforeBalance(openAfterBalance);
            if(tBox.getBoxType().equals(Constants.BOXTYPE0)){
                backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE0);
                if(openAfterBalance.compareTo(price) >=0){
                    /**普通箱子开箱 扣除余额*/
                    openAfterBalance = openAfterBalance.subtract(price);
                }else if(openAfterBalance.compareTo(BigDecimal.ZERO) > 0 && openAfterBalance.compareTo(price) < 0){
                    openAfterSecondCurrency = openAfterSecondCurrency.subtract(price.subtract(openAfterBalance));
                    openAfterBalance = BigDecimal.ZERO;
                }else {
                    openAfterSecondCurrency = openAfterSecondCurrency.subtract(price);
                }
                backpack.setOpenBoxPrice(price);
            }else if (tBox.getBoxType().equals(Constants.BOXTYPE4)) {
                backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE12);
                if(openAfterBalance.compareTo(price) >=0){
                    /**普通箱子开箱 扣除余额*/
                    openAfterBalance = openAfterBalance.subtract(price);
                }else if(openAfterBalance.compareTo(BigDecimal.ZERO) > 0 && openAfterBalance.compareTo(price) < 0){
                    openAfterSecondCurrency = openAfterSecondCurrency.subtract(price.subtract(openAfterBalance));
                    openAfterBalance = BigDecimal.ZERO;
                }else {
                    openAfterSecondCurrency = openAfterSecondCurrency.subtract(price);
                }
                backpack.setOpenBoxPrice(price);
            }else if (tBox.getBoxType().equals(Constants.BOXTYPE5)) {
                backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE13);
                backpack.setOpenBoxPrice(BigDecimal.ZERO);
            }else {
                backpack.setGoodsBelongingType(Constants.GOOGSBLTYPE14);
                backpack.setOpenBoxPrice(BigDecimal.ZERO);
            }
            backpack.setGoodsBelongingId(bean.getGoodsBelongingId());
            backpack.setGoodsBelongingName(tBox.getBoxName());
            backpack.setGoodsPrice(bean.getGoodsPrice());
            backpack.setGoodsExprice(bean.getGoodsExprice());
            backpack.setDelFlag(Constants.SUCCESS);
            backpack.setCreateTime(DateUtils.getNowDate());
            backpack.setGoodsType(bean.getGoodsType());
            backpack.setGoodsNum(1);
            backpack.setUserPromotersId(tUser.getUserPromotersId());
            backpack.setAuditStatus(Constants.AUDITSTATUS0);
            backpack.setBbGoodsName(bean.getGoodsName());
            backpack.setBbGoodsPic(bean.getGoodsPic());
            backpack.setBbGoodsGrate(bean.getGoodsGrate());
            if (!tUser.getUserType().equals(Constants.USERTYPE1)) {
                backpack.setRuleType(Constants.RULE_TYPE0);
            }
//            backpack.setOpenAfterBalance(openAfterBalance);
            backpack.setBbStatus(Constants.BBSTATUS0);
            backpack.setUserSeed(userSeed);
            backpack.setServerSeed(serverSeed);
            backpack.setCommonHash(commonHash);
            backpack.setRollValue(rollValue);
            backpack.setNonce(nonce);
            backpack.setRollValueRange(bean.getRollValueRange());
            backpackList.add(backpack);
            resultList.add(bean);
        }
        /**批量插入背包信息表*/
        int row = backpackMapper.insertTBackpackBatch(backpackList);
        if(tWarReceive != null){
            /**表示战令箱子*/
            tWarReceiveMapper.updateTWarReceive(tWarReceive);
        }
        BigDecimal fee = balance.subtract(openAfterBalance);
        fee = fee.add(secondCurrency.subtract(openAfterSecondCurrency));
        /**余额变更记录表*/
        TBalanceChange balanceChange = new TBalanceChange();
        balanceChange.setUserId(userId);
        balanceChange.setBalanceBefore(balance);
        balanceChange.setBalanceAfter(openAfterBalance);
        balanceChange.setOperationType(Constants.OPERATIONTYPE1);
        balanceChange.setFrequency(num);
        balanceChange.setFee(fee);
        balanceChange.setCorrespondingid(boxId);
        balanceChange.setCreateTime(DateUtils.getNowDate());
        balanceChange.setSecondCurrencyBefore(secondCurrency);
        balanceChange.setSecondCurrencyAfter(openAfterSecondCurrency);

        /**新增消费计量值*/
        BigDecimal cv = fee.multiply(BigDecimal.valueOf(0.5)).setScale(2,BigDecimal.ROUND_HALF_UP);
        balanceChange.setConsumeValue(cv);

        /**获利价值*/
        BigDecimal totalPrice = backpackList.stream().map(TBackpack::getGoodsPrice).reduce(BigDecimal.ZERO,BigDecimal::add);
        balanceChange.setProfitPrice(totalPrice);
        balanceChange.setCostFee(fee);
        balanceChangeMapper.insertTBalanceChange(balanceChange);

        /**修改用户的余额*/
        tUser.setUserBalance(openAfterBalance);
        tUser.setSecondCurrency(openAfterSecondCurrency);
        tUser.setUpdateTime(DateUtils.getNowDate());
        int row1 = tUserMapper.updateTUserBalance(tUser);
        if (row1 == 0) {
            throw new CustomException("网络延迟,请重新抽奖! ");
        }

        /**计算战令和vip等级 经验*/
        if(cv.compareTo(BigDecimal.ZERO)>0){
            tVipUserService.vipStreamHandleV2(tUser.getUserId(),cv);
            tWarService.computeWarFlow(tUser.getUserId(),cv);
        }
        return Response.success(resultList);
    }

    @Override
    public Response<Map> openBoxHashTest(String userSeed,String boxId, int cs) {
        LinkedHashMap map = new LinkedHashMap();
        TBox tBox = tBoxMapper.selectTBoxById(boxId);
        map.put("箱子名称",tBox.getBoxName());
        map.put("箱子单价",tBox.getBoxPrice().toPlainString());
        map.put("开箱次数",cs);
        BigDecimal costfee = tBox.getBoxPrice().multiply(BigDecimal.valueOf(cs));
        map.put("花费总金额",costfee.toPlainString());
        List<TGoods> goodsList = tGoodsMapper.boxGoodsList(Constants.GOOGSBLTYPE0, boxId);
        Map<String, String> goodsIdMap = goodsList.stream().collect(Collectors.toMap(TGoods::getGoodsId,TGoods::getRollValueRange));
        Map<String, TGoods> goodsMap = goodsList.stream().collect(Collectors.toMap(TGoods::getGoodsId,t -> t));

        BigDecimal totalGoodsPrice = BigDecimal.ZERO;

        List<TGoods> resultList = new ArrayList<>();
        for(int i=0;i<cs;i++) {
            /**服务端种子*/
            String serverSeed = HashUtil.generateServerSeed();
            /**随机整数*/
            int nonce = HashUtil.generateNonce();
            /**公共hash*/
            String commonHash = HashUtil.commonHashCode(userSeed, serverSeed, nonce);
            /**roll值*/
            Long rollValue = HashUtil.rollValue(commonHash);

            String goodsId = RollValueUtil.rollItem(rollValue.intValue(), goodsIdMap);
            TGoods bean1 = goodsMap.get(goodsId);
            totalGoodsPrice = totalGoodsPrice.add(bean1.getGoodsPrice());
            resultList.add(bean1);
        }
        map.put("开出饰品总价值",totalGoodsPrice.toPlainString());
        map.put("开箱盈利",totalGoodsPrice.subtract(costfee).toPlainString());
        map.put("利润率",BigDecimal.ONE.subtract(costfee.divide(totalGoodsPrice,6)));

        Map<String, BigDecimal> totalPriceMap = resultList.stream()
                .collect(Collectors.groupingBy(TGoods::getGoodsId, Collectors.reducing(BigDecimal.ZERO, TGoods::getGoodsPrice, BigDecimal::add)));

        Map<String, Long> countMap = resultList.stream()
                .collect(Collectors.groupingBy(TGoods::getGoodsId, Collectors.counting()));

        List<Map<String, Object>> result = goodsList.stream()
                .map(goods -> {
                    String goodsId = goods.getGoodsId();
                    String goodsName = goods.getGoodsName();

                    Map<String, Object> map1 = new HashMap<>();
                    map1.put("goodsId", goodsId);
                    map1.put("goodsName", goodsName);
                    map1.put("totalPrice", 0);
                    map1.put("probability", 0);
                    map1.put("totalCount",0);

                    Long totalCount = countMap.get(goodsId);
                    if(totalCount != null){
                        BigDecimal totalPrice = totalPriceMap.get(goodsId);
                        double probability = (double) totalCount / resultList.size();
                        map1.put("totalPrice", totalPrice);
                        map1.put("probability", round(probability, 6));
                        map1.put("totalCount",totalCount);
                    }
                    return map1;
                })
                .collect(Collectors.toList());
        map.put("开出饰品集合:",result);
        return Response.success(map);
    }

    public static double round(double value, int places) {
        if (places < 0) throw new IllegalArgumentException();

        BigDecimal bd = BigDecimal.valueOf(value);
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }

    @Override
    public Response hashTest(String userSeed, int cs,int partitionSize) {
        List<Integer> numbers = new ArrayList<>();
        for(int i=0;i<cs;i++){
            /**服务端种子*/
            String serverSeed = HashUtil.generateServerSeed();
            /**随机整数*/
            int nonce = HashUtil.generateNonce();
            /**公共hash*/
            String commonHash = HashUtil.commonHashCode(userSeed, serverSeed, nonce);
            /**roll值*/
            Long rollValue = HashUtil.rollValue(commonHash);
            numbers.add(rollValue.intValue());
        }
        // 计算总区间段数量
        int totalPartitions = 1000000 / partitionSize + 1;

        // 初始化区间段数量统计 Map
        LinkedHashMap<String, Integer> counts = new LinkedHashMap<>();
        for (int i = 0; i < totalPartitions; i++) {
            int start = i * partitionSize;
            int end = Math.min((i + 1) * partitionSize - 1, 1000000);
            counts.put("[" + start + "-" + end + "]", 0);
        }

        // 统计每个区间段的数量
        for (int num : numbers) {
            int index = num / partitionSize; // 计算当前数属于哪个区间段
            String key = "[" + (index * partitionSize) + "-" + Math.min(((index + 1) * partitionSize - 1), 1000000) + "]";
            counts.put(key, counts.get(key) + 1);
        }

        return Response.success(counts);
    }
}
